#include "Player/PlayerDataMachine.h"
#include "Player/PlayerData.h"

#include "Network/Packages/PlayerDataPackage.h"
#include "Network/Packages/EntityPackage.h"
#include "Log.h"
#include "GameSingleton.h"
#include "Expand/EventManager.h"
#include "Components/ComponentPlayer.h"
#include "Components/ComponentHealth.h"
#include "Components/ComponentSickness.h"
#include "Components/ComponentBody.h"
#include "Components/ComponentFlu.h"
#include "Components/ComponentVitalStats.h"
#include "Components/ComponentCreature.h"
#include "Components/ComponentOnFire.h"
#include "Components/ComponentAntiCheat.h"

#include "Managers/BlocksManager.h"
#include "Subsystems/SubsystemTerrain.h"
#include "Subsystems/SubsystemPlayers.h"
#include "Network/PackageManager.h"
#include <cfloat>

namespace PocketSurvival
{
    PlayerMachine::PlayerMachine(PlayerData *playerData) : m_playerData(playerData), EasyMachine(PlayerMachineState::Enter)
    {
        enter();
    }

    static float ScoreNoIntroSpawnPosition(Vector3 desiredSpawnPosition, int32_t x, int32_t y, int32_t z, SubsystemTerrain *subsystemTerrain, PlayerData* myself)
    {
        float num = -0.01f * Vector3::Distance(Vector3(x, y, z), desiredSpawnPosition);
        if (y < 1 || y >= 255)
        {
            num -= 100.0f;
        }
        Block *obj      = GameSingleton::blocksManager->blocks[subsystemTerrain->getCellContents(x, y - 1, z)];
        Block *block    = GameSingleton::blocksManager->blocks[subsystemTerrain->getCellContents(x, y, z)];
        Block *block2   = GameSingleton::blocksManager->blocks[subsystemTerrain->getCellContents(x, y + 1, z)];
        if (obj->IsTransparent)
        {
            num -= 10.0f;
        }
        if (obj->IsCollidable == false)
        {
            num -= 10.0f;
        }
        if (block->IsCollidable)
        {
            num -= 10.0f;
        }
        if (block2->IsCollidable)
        {
            num -= 10.0f;
        }
        std::vector<std::shared_ptr<PlayerData>> playerDataVec;
        GameSingleton::singletonPtr->getSingleton<SubsystemPlayers>()->getAllPlayerData(playerDataVec);

        for (auto &playersDatum : playerDataVec)
        {
            if (playersDatum.get() != myself && Vector3::DistanceSquared(playersDatum->spawnPosition, Vector3(x, y, z)) < MathUtils::Sqr(2))
            {
                num -= 1.0f;
            }
        }
        return num;
    }

    
    void PlayerMachine::enter()
    {
        switch (m_currentState)
        {
        case PlayerMachineState::Enter:
            MACHINE_DELEGATE()
            {
                std::shared_ptr<PlayerDataPackage> newPackage = std::make_shared<PlayerDataPackage>(m_playerData->shared_from_this(), PlayerDataPackageType::AddPlayer);
                
                // 06.02 必须有这个
                if(m_playerData->isNewCreate == false)
                {
                    newPackage->sendType = PackageSendType::EXCEPT;
                    newPackage->client = m_playerData->client;
                }
                GameSingleton::packageManager->addSendPackageToQueue(newPackage);
            }
            break;
        case PlayerMachineState::Playing:
            MACHINE_DELEGATE()
            {

            }
            break;
        case PlayerMachineState::Dead:
            MACHINE_DELEGATE()
            {

            }
            break;
        case PlayerMachineState::Restart:
            MACHINE_DELEGATE()
            {

            }
            break;
        }
    }

    void PlayerMachine::update(float dt)
    {
        switch (m_currentState)
        {
        case PlayerMachineState::Enter:
            MACHINE_DELEGATE()
            {
                if(m_playerData->getRequestChunkSize() > 0)
                {
                    changeTo(PlayerMachineState::Playing);
                }
            }
            break;
        case PlayerMachineState::Playing:
            MACHINE_DELEGATE()
            {
                m_playerData->updateRequestChunk();
            }
            break;
        case PlayerMachineState::Dead:
            MACHINE_DELEGATE()
            {
                m_playerData->updateRequestChunk();
            }
            break;
        case PlayerMachineState::Restart:
            MACHINE_DELEGATE()
            {
                ComponentPlayer *componentPlayer = m_playerData->componentPlayer;

                // 新添加的玩家实体要告知所有客户端
                componentPlayer->componentHealth->health = 1.0f;
                componentPlayer->componentHealth->air = 1.0f;
                componentPlayer->componentSickness->sicknessDuration = 0.0f;
                componentPlayer->componentFlu->fluDuration = 0.0f;
                componentPlayer->componentHealth->componentOnFire->fireDuration = 0.0f;

                SubsystemTerrain *subsystemTerrain = GameSingleton::singletonPtr->getSingleton<SubsystemTerrain>();
                Vector3 &spawnPosition = m_playerData->spawnPosition;
                Vector3 vector;
                float num = FLT_MIN;
                for (int32_t i = -8; i <= 8; i++)
                {
                    for (int32_t j = -8; j <= 8; j++)
                    {
                        for (int32_t k = -8; k <= 8; k++)
                        {
                            int32_t num2 = Terrain::ToCell(spawnPosition.posX) + i;
                            int32_t num3 = Terrain::ToCell(spawnPosition.posY) + j;
                            int32_t num4 = Terrain::ToCell(spawnPosition.posZ) + k;
                            float num5 = ScoreNoIntroSpawnPosition(spawnPosition, num2, num3, num4, subsystemTerrain, m_playerData);
                            if (num5 > num)
                            {
                                num = num5;
                                vector = Vector3(num2, num3, num4);
                            }
                        }
                    }
                }
                vector.posX += 0.5f;
                vector.posY += 0.01f;
                vector.posZ += 0.5f;

                componentPlayer->componentBody->setPosition(spawnPosition + vector);
                componentPlayer->componentAntiCheat->lastPosition = spawnPosition + vector;
                componentPlayer->componentVitalStats->setFood(0.1f);
                componentPlayer->componentVitalStats->setTemperature(12.0f);
                componentPlayer->componentVitalStats->setWetness(0.0f);
                componentPlayer->componentVitalStats->setStamina(1.0f);
                componentPlayer->componentVitalStats->setSleep(1.0f);

                componentPlayer->componentVitalStats->environmentTemperature = componentPlayer->componentVitalStats->temperature;

                // 捕捉玩家复活
                GameSingleton::eventManager->playerEvent->playerRestart(componentPlayer);

                std::shared_ptr<EntityPackage> package = std::make_shared<EntityPackage>(componentPlayer->entity, EntityPackageType::LoadOne);
                GameSingleton::packageManager->addSendPackageToQueue(package);
                changeTo(PlayerMachineState::Playing);
            }
            break;
        }
    }

    void PlayerMachine::leave() {}

}